package ie.dit.reg08.attSelector;

import ie.dit.reg08.manager.*;

import java.util.*;
/*
 * Uses a greedy search with no backtracking to construct a distinguishing description
 * Select next property to use based on selecting from the set of attributes not tested for
 * inclusion in the description the attribute with the highest score using the following
 * scoring equation:  
 * (attribute freq/total number of attribute instances) * (number of remaining distractors distinguished/total number of distractors) 
 */
public class Incremental3 implements greInterface {
	String id;
	boolean distinguishing;
	Hashtable description;
	Domain domain;
	TreeMap tmAttFreq;
	float totalCount;
	float numDistractors;
	
	/*
	 * Note the boolean dummy variable that is passed into gre() is not used by the function.
	 * It is simply there to make the function signature match the interface defintion.
	 */
	public Incremental3(Trial t, TreeMap tm, int total, boolean includetype) {
		boolean dummy = true;
		id =  t.getID();		
		domain = t.getDomain();
		distinguishing = false;
		tmAttFreq = tm;
		totalCount = total;
		numDistractors = 6;
		description = new Hashtable();
		description = gre(t, includetype, dummy);
	}
	
	public Hashtable getDescripton(){
		return description;
	}
	
	/*
	 * Note the boolean dummy variable that is passed into gre() is not used by the function.
	 * It is simply there to make the function signature match the interface defintion.
	 */
	public Hashtable gre(Trial t, boolean includetype, boolean dummy) {
		Vector vDistractors;
		Vector vPreviousProperties = new Vector();
		String sNextProperty;
		Entity target = t.getDomain().getTarget();
		Hashtable htTargetAttributes = target.getAttributes();
			
		Enumeration e = htTargetAttributes.keys();
		while (e.hasMoreElements()) {
							
			sNextProperty = nextAtt(distDist(htTargetAttributes, vPreviousProperties, domain.distractorSet(description)));
			vPreviousProperties.add(sNextProperty);
			
			//TODO: update gre in incremental 3 to capture
			//properties that don't belong to the target
			System.err.println("update gre function to handle properties that don't belong to the domain!");
			System.exit(1);
			if (htTargetAttributes.containsKey(sNextProperty)) {
				vDistractors = addAttribute(sNextProperty,
						(String) htTargetAttributes.get(sNextProperty));
				if (vDistractors.isEmpty()) {
					distinguishing = true;
					return description;
				}
			}
		}
		return description;
	}
	
	public boolean isDistinguishing() {
		return distinguishing;
	}
	
	private Vector addAttribute(String nextProperty, String value) {
		int numdistractors = (domain.distractorSet(description)).size();
		description.put(nextProperty, value);
		if (numdistractors > domain.distractorSet(description).size()) {
			//ok leave the added attribute in the description
		} else {
			description.remove(nextProperty);
		}
		return domain.distractorSet(description);
	}

	
	/*
	 * Arg1 = a Hashtable with keys = target attributes not tested for inclusion in
	 * the description yet, values = number of distractors they distinguish the target from
	 * Return value = the target attribute in the set of attributes
	 * not tested for inclusion in the description with the highest score in the 
	 * based on the following equation:
	 * (attribute freq/total number of attribute instances) * (number of remaining distractors distinguished/total number of distractors) 
	 */
	public String nextAtt(Hashtable distDistinguished) {
		String s = "";
		String tmp;
		float max = 0;
		int dist;
		int freq;
		float score;
		
		
		Set ks = distDistinguished.keySet();
		Iterator i = ks.iterator();
		while(i.hasNext()) {
			tmp = (String)i.next();
			dist = ((Integer)distDistinguished.get(tmp)).intValue();
			freq = getFrequency(tmp);
			score = (dist/numDistractors) * (freq/totalCount);
			if(score > max) {
				max = score;
				s = tmp;
			}
		}
		
		return s;
	}

	/*
	 * Retrieves the frequency of an attribute (arg1) from the tmAttFreq data structure
	 * Returns -1 if it can't find the attribute.
	 */
	private int getFrequency(String att) {
		int freq;
		String s;
		Integer k;
		Set ks = tmAttFreq.keySet();
		Iterator j = ks.iterator();
		while(j.hasNext()) {
			k = (Integer)j.next();
			s = (String)tmAttFreq.get(k);
			if(att.equals(s)) {
				return k.intValue();
			}
		}
		return -1;
	}
	
	/*
	 * Arg1 = a HashMap containing a the targets attributes (Strings) and values (Strings)
	 * Arg2 = a vector containing the set of attributes previously tested for inclusion in
	 * the description
	 * Arg3 = a vector containing the distractors the fulfill the current description
	 * Return value a Hashtable with keys = target attributes not tested for inclusion in
	 * the description yet, values = number of distractors they distinguish the target from
	 */
	public Hashtable distDist(Hashtable ht, Vector vPrevious, Vector vDistractors) {
		String tmpA, tmpV;
		Entity ent;
		Hashtable htTmp, htReturn;
		String mostDistinguishing = null;
		int maxExcluded = 0;
		int excluded;
		
		Iterator i;
		htTmp = new Hashtable();
		htReturn = new Hashtable();
		Enumeration e = ht.keys();
		while(e.hasMoreElements()) {
			excluded = 0;
			tmpA = (String)e.nextElement();	
			//don't consider properties that have already been checked for
			//inclusion in the description
			if(!vPrevious.contains(tmpA)) {		
				htTmp.put(tmpA,(String)ht.get(tmpA));
				i = vDistractors.iterator();
				while(i.hasNext()) {
					ent = (Entity)i.next();
					if(!ent.isTarget()) {
						if(!ent.fulfills(htTmp)) {
							excluded++;
						}
					}
				}
			}
			htTmp.remove(tmpA);
			htReturn.put(tmpA, new Integer(excluded));
		}
		return htReturn;
	}
	
	public String getID() {
		return id;
	}
	
	public String xmlDescription() {  
		  String s = "<TRIAL ID=\"" + id + "\">\n";
		  s = s + "<DESCRIPTION>\n";
		  
		  Enumeration e = description.keys();
		  String k;
		  while(e.hasMoreElements()) {
			  k = (String)e.nextElement();
			  s = s + "<ATTRIBUTE NAME=\"" + k + "\" VALUE=\"" + description.get(k) + "\"/>\n";
		  }
		  s = s + "</DESCRIPTION>\n";
		  s = s + "</TRIAL>\n";
		  return s;
	}
}
